package com.wry.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * <h1> JDK动态代理 </h1>
 *
 * @author wry
 * @since 2025.04.04
 */
public class JdkProxy {

    public static void main(String[] args) {
        TrainStation trainStation = new TrainStation();
        UniversalIntermediary universalIntermediary = new UniversalIntermediary(trainStation);
//        BuyTickets proxy = (BuyTickets) universalIntermediary.getProxy();
        BuyTickets proxy = (BuyTickets) Proxy.newProxyInstance(universalIntermediary.getClass().getClassLoader(), // 指定代理对象的类加载器
                trainStation.getClass().getInterfaces(), // 代理对象需要实现的接口，可以同时指定多个接口
                universalIntermediary);
        proxy.issueTickets();
    }

    /**
     * 车站买票
     */
    interface BuyTickets {
        void issueTickets();
    }

    /**
     * 车站  被代理对象
     */
    static class TrainStation implements BuyTickets {

        @Override
        public void issueTickets() {
            System.out.println("我是车站-出票完成！");
        }
    }

    /**
     * JDK代理（车站）
     */
    static class UniversalIntermediary implements InvocationHandler {

        private TrainStation trainStation;

        public UniversalIntermediary(TrainStation trainStation) {
            this.trainStation = trainStation;
        }

        // 方法增强
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            askForTickets();
            Object invoke = method.invoke(trainStation, args);
            getTheTicket();
            return invoke;
        }

        public void askForTickets() {
            System.out.println("我是代理-询问使用车票吗？需要给我钱把");
            System.out.println("我是代理-还有余票啊！");
        }

        public void getTheTicket() {
            System.out.println("我是代理-帮你买到车票啦！付钱给车站");
        }

        public Object getProxy(){
            // 会返回一个实现了指定接口的代理对象，对该对象的所有方法调用都会转发给InvocationHandler.invoke()方法
            return Proxy.newProxyInstance(this.getClass().getClassLoader(), // 指定代理对象的类加载器
                    trainStation.getClass().getInterfaces(), // 代理对象需要实现的接口，可以同时指定多个接口
                    this); // 方法调用的实际处理者，代理对象的方法调用都会转发到这里
        }
    }
}
